import { JJUtil, JJLog } from './../util/index'
import { JJError } from './../bizUtil/index.js';

let requestCount = 0

class JJRequestAgent {
    static instance
    requestList = [];
    readyRequestList = []

    static sharedInstance() {
        if (false === this.instance instanceof this) {
            this.instance = new this();
        }
        return this.instance;
    }

    start(request) {
        if (request.isWaitingLastSameRequestResponse && this.isExistSameRequestInRequesting(request)) {
            this.addRequestToReadyRequestList(request)
            return
        }

        this.__start(request)
    }

    __start(request) {
        this.addRequest(request)

        if (!request.isAllowBeginSendRequest()) {
            this.handleNetworkFailRequestResult(request, JJError.networkReuqestFailError)
            return
        }

        this.__startRequest(request)
    }

    __startRequest(request) {
        request.turnOnTimer()

        let url = request.buildRequestUrl()
        const header = request.getRequestHeader()
        const paramters = request.requestParameter()
        const method = request.methodType
        const credential = request.getRequestCredentials()
        //const mode = request.getRequestMode()

        let body = ''
        for (let key in paramters) {
            body += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(paramters[key])
        }
        if (JJUtil.isNotEmpty(body)) {
            body = body.slice(1)
        }

        const me = this

        let requestObjc = { method: method, headers: header, credential:credential }
        if (request.methodType === request.JJRequestMethod.Post) {
            requestObjc.body = body;
        } else if (request.methodType === request.JJRequestMethod.Get) {
            if (JJUtil.isNotEmpty(body)) {
                const index = url.indexOf('?')
                if (index < 0) {
                    url = url + '?' + body
                } else {
                    url = url.replace('?', '?' + body + '&')
                }
            }
        }

        fetch(url, requestObjc).then((response) => {
            request.responseCode = response.status;
            request.responseHeader = response.headers;
            if (response.status >= 200 && response.status <= 299) {
                request.setResponseData(response).then((value) => {
                    request.responseData = value
                    me.handleNetworkSuccessRequestResult(request, value);
                })
            } else {
                me.handleNetworkFailRequestResult(request, response.data);
            }
        }).catch((error) => {
            me.handleNetworkFailRequestResult(request, error);
        })
    }

    stop(request) {
        this.removeRequest(request);

        if (request.isWaitingLastSameRequestResponse) {
            this.__startReadyRequestListWithRequest(request)
        }
    }

    handleNetworkSuccessRequestResult(request, response) {
        request.cancelTimeoutTimer();

        const index = this.requestList.indexOf(request);
        if (index < 0) {
            return;
        }

        this.removeRequest(request);

        const me = this

        request.requestCompleteFilter(response).then((value) => {
            const isSuccess = request.successForBusiness(value)
            const result = request.filterSuccessCallBackValue(isSuccess, value);

            JJLog.info(`(${++requestCount})` + request.toString())
            if (isSuccess) {
                JJLog.info(`(${requestCount})【Response Success】content: ` + JSON.stringify(result))
            } else {
                JJLog.error(`(${requestCount})【Response Success】Business Fail, content: ` + JSON.stringify(result))
            }

            if (JJUtil.isNotNull(request.networkSuccessCallBack)) {
                request.networkSuccessCallBack(isSuccess, result, request.otherInfo);
            }

            if (request.isNeedPostResponseNotification) {
                request.postResponseNotification(true, isSuccess, result, null, request.otherInfo)
            }

            me.__startReadyRequestList(request, true, isSuccess, result, null, value)
        });
    }

    handleNetworkFailRequestResult(request, error) {
        request.cancelTimeoutTimer();

        const index = this.requestList.indexOf(request);
        if (index < 0) {
            return;
        }

        this.removeRequest(request);

        const me = this

        request.requestFailedFilter(error).then((value) => {
            const errorObj = request.filterFailCallBackValue(value)

            JJLog.info(`(${++requestCount})` + request.toString())
            JJLog.error(`(${requestCount})【Response Fail】error: ` + JSON.stringify(error));

            if (JJUtil.isNotNull(request.networkFailCallBack)) {
                request.networkFailCallBack(errorObj, request.otherInfo);
            }

            if (request.isNeedPostResponseNotification) {
                request.postResponseNotification(false, false, null, errorObj, request.otherInfo)
            }

            me.__startReadyRequestList(request, false, false, null, errorObj, null)
        });
    }

    isExistSameRequestInRequesting(request_) {
        const length = this.requestList.length
        for (let i = 0; i < length; ++i) {
            const tempRequest = this.requestList[i]
            if (request_.identity === tempRequest.identity) {
                return true
            }
        }

        return false
    }

    addRequest(request) {
        const index = this.requestList.indexOf(request);
        if (index >= 0) {
            return;
        }
        this.requestList.push(request);
    }

    removeRequest(request) {
        const index = this.requestList.indexOf(request);
        if (index >= 0) {
            this.requestList.splice(index, 1);
        }
    }

    addRequestToReadyRequestList(request) {
        const index = this.readyRequestList.indexOf(request);
        if (index >= 0) {
            return;
        }
        this.readyRequestList.push(request);
    }

    removeRequestToReadyRequestList(request) {
        const index = this.readyRequestList.indexOf(request);
        if (index >= 0) {
            this.readyRequestList.splice(index, 1);
        }
    }

    __startReadyRequestList(lastRequest, isNetworkSuccess, isBusinessSuccess, response, errorObj, originalResponse) {
        const length = this.readyRequestList.length
        let deleteIndexList = []
        for (let i = 0; i < length; ++i) {
            let tempRequest = this.readyRequestList[i]
            if (lastRequest.identity === tempRequest.identity) {
                deleteIndexList.push(i)

                if (JJUtil.isNotNull(tempRequest.isSendRequestWhenLastSameRequestResponseCallBack)
                    && !tempRequest.isSendRequestWhenLastSameRequestResponseCallBack(lastRequest, isNetworkSuccess, isBusinessSuccess, response, errorObj, originalResponse)) {
                    if (isNetworkSuccess) {
                        tempRequest.otherInfo.responseData = originalResponse ? originalResponse : {}
                        tempRequest.networkSuccessCallBack && tempRequest.networkSuccessCallBack(isBusinessSuccess, response, tempRequest.otherInfo)
                    } else {
                        tempRequest.networkFailCallBack && tempRequest.networkFailCallBack(errorObj, tempRequest.otherInfo)
                    }

                    if (tempRequest.isNeedPostResponseNotification) {
                        tempRequest.postResponseNotification(isNetworkSuccess, isBusinessSuccess, response, errorObj, tempRequest.otherInfo)
                    }
                } else {
                    this.__start(tempRequest)
                    break
                }
            }
        }

        for (let j = deleteIndexList.length; j > 0; --j) {
            this.readyRequestList.splice(deleteIndexList[j - 1], 1) // 从队列删除
        }
    }

    __startReadyRequestListWithRequest(request_) {
        const length = this.readyRequestList.length
        for (let i = 0; i < length; ++i) {
            let tempRequest = this.readyRequestList[i]
            if (request_.identity === tempRequest.identity) {
                this.readyRequestList.splice(i, 1)
                this.__start(tempRequest)
                return
            }
        }
    }

    __startAllReadyRequestList() {
        const length = this.readyRequestList.length
        for (let i = 0; i < length; ++i) {
            const request = this.readyRequestList[i]
            if (JJUtil.isNotNull(request)) {
                this.__start(request)
            }
        }

        this.readyRequestList = []
    }
}

export default JJRequestAgent;
